package cn.madis.ymcc.service.impl;

import cn.madis.exception.GlobalException;
import cn.madis.ymcc.UaaFeignClient;
import cn.madis.ymcc.domain.*;
import cn.madis.ymcc.dto.RedisPhoneCodeDto;
import cn.madis.ymcc.dto.UserRegisterDTO;
import cn.madis.ymcc.mapper.*;
import cn.madis.ymcc.result.JSONResult;
import cn.madis.ymcc.service.IUserService;
import cn.madis.ymcc.util.AssertUtil;
import cn.madis.ymcc.util.BitStatesUtils;
import cn.madis.ymcc.util.StrUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author Zt
 * @since 2022-08-04
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private LoginMapper loginMapper;

    @Autowired
    private UaaFeignClient uaaFeignClient;

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private UserBaseInfoMapper userBaseInfoMapper;

    @Autowired
    private UserRefeMapper userRefeMapper;

    @Autowired
    private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(UserRegisterDTO dto) {
        //mobile---查数据库  有没有这个手机号 有  抛异常
        AssertUtil.isFalse(existUserByPhone(dto.getMobile()),"用户已经注册过了");
        //smsCode---到redis里面去查  看是不是一样 如果不一样  抛异常
        RedisPhoneCodeDto smsCodeRedisValueByPhone = getSMSCodeRedisValueByPhone(dto.getMobile());
        AssertUtil.isNotNull(smsCodeRedisValueByPhone,"没有找到验证码");
        String code = smsCodeRedisValueByPhone.getCode();
        String smsCode = dto.getSmsCode();
        AssertUtil.isTrue(StringUtils.equals(code,smsCode),"验证码错误");
        //4.判断推荐码
        Long userId = referralCode(dto.getCode());
        //3.因为user需要存loginId  所以先存login表存好之后需要给我一个loginId
        Long loginId = insertLoginAndGetLoginId(dto);
        //4.保存user相关的表user  user-base-info  user-account
        insertRelateUserTables(dto,loginId,userId);
        //5.删除redis中对应的手机验证码
        redisTemplate.delete("phoneCode"+dto.getMobile());
    }


    /**
     * 根据传入的手机号  判断是否已经存在该用户
     *
     * @return
     */

    boolean existUserByPhone(String phone) {
        EntityWrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("phone",phone);
        List<User> users = userMapper.selectList(wrapper);
        return users != null && users.size()>0;
    }

    /**
     * 根据传入的手机号  判断redis中是否有key
     * @param phone
     * @return
     */
    public RedisPhoneCodeDto getSMSCodeRedisValueByPhone(String phone) {
            String key = "phoneCode" + phone;
            return (RedisPhoneCodeDto)redisTemplate.opsForValue().get(key);
    }


    /**
     * 插入login表  并返回loginId
     * @param dto
     * @return
     */
    public Long insertLoginAndGetLoginId(UserRegisterDTO dto) {
        Login login = new Login();
        login.setUsername(dto.getMobile());
        login.setPassword(passwordEncoder.encode(dto.getPassword()));
        login.setType(dto.getRegChannel());
        JSONResult loginResult = uaaFeignClient.saveOrUpdate(login);
        Object data = loginResult.getData();
        String s = JSON.toJSONString(data);
        Login login1 = JSONObject.parseObject(s, Login.class);
        return login1.getId();
    }

    /**
    * @Title: referralCode
    * @Description: 推荐码判断
    * @Author: Mr.She
    * @Version: 1.0
    * @Date:  2022/8/8 10:51
    * @Parameters:
    * @Return
    */
    Long referralCode(String code) {
        if (StringUtils.isEmpty(code)){
            return null;
        }
        Wrapper<UserRefe> wrapper = new EntityWrapper<UserRefe>().eq("code", code);
        List<UserRefe> userRefes = userRefeMapper.selectList(wrapper);
        if (userRefes.size() > 0){
            Long userId = userRefes.get(0).getUserId();
            return userId;
        }else {
            throw new GlobalException("推荐码错误");
        }
    }


    void insertRelateUserTables(UserRegisterDTO dto, Long loginId, Long userId) {
        User user = insertUserAndGetUser(dto,loginId);
        insertUserBaseInfo(user,dto,userId);
        insertUserAccount(user);
    }


    /**
     * 插入user表  并返回user对象
     * @param dto
     * @param loginId
     * @return
     */
    User insertUserAndGetUser(UserRegisterDTO dto , Long loginId){
        User user = new User();
        user.setPhone(dto.getMobile());
        user.setCreateTime(new Date().getTime());
        user.setNickName(dto.getMobile());
        Long states = BitStatesUtils.batchAddState(0L,
                BitStatesUtils.OP_REGISTED,
                BitStatesUtils.OP_ACTIVED,
                BitStatesUtils.OP_AUTHED_PHONE
        );
        user.setBitState(states);
        user.setLoginId(loginId);
        userMapper.insert(user);
        //保存userrefe表推荐码表
        String code = StrUtils.getRandomString(4);
        Long id = user.getId();
        UserRefe userRefe = new UserRefe();
        userRefe.setCode(code);
        userRefe.setUserId(id);
        userRefeMapper.insert(userRefe);
        return user;
    }

    /**
     * 插入user base info 表
     * @param user
     * @param dto
     * @param userId
     */
    void insertUserBaseInfo(User user, UserRegisterDTO dto, Long userId){
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(user.getId());
        userBaseInfo.setCreateTime(user.getCreateTime());
        userBaseInfo.setRegChannel(dto.getRegChannel());
        userBaseInfo.setReferId(userId);
        userBaseInfoMapper.insert(userBaseInfo);
    }


    /**
     * 插入user account 表
     * @param user
     */
    void insertUserAccount(User user){
        UserAccount userAccount = new UserAccount();
        userAccount.setId(user.getId());
        userAccount.setCreateTime(user.getCreateTime());
        userAccountMapper.insert(userAccount);
    }


}
